#!/usr/bin/env python
# -*- coding: utf-8 -*-

import copy
import shelve
import pickle
from utils import pprint, get_split_variants

PATH = '../smart-cook/data/morph/'

class BTree():
  def __init__(self):
	pass
	

	
class ProxyIntGetter():
  def __init__(self, filename):
    self.data = shelve.open(filename)

  def __getitem__(self, int_key):
    return copy.copy(self.data[str(int_key)])

  def __contains__(self, int_key):
    return self.data.has_key(str(int_key))

class ProxyUnicodeGetter():
  def __init__(self, filename):
    self.data = shelve.open(filename)

  def __getitem__(self, unicode_key):
    return copy.copy(self.data[unicode_key.encode('utf-8')])

  def __contains__(self, unicode_key):
    return self.data.has_key(unicode_key.encode('utf-8'))


class ShelveDataSource():
  def load(self):
    self.lemmas = ProxyUnicodeGetter(PATH + 'lemmas.shv')
    self.rules = ProxyIntGetter(PATH + 'rules.shv')
    self.gramtab = ProxyUnicodeGetter(PATH + 'gramtab.shv')
    self.prefixes = pickle.load(open(PATH + 'prefixes.pkl', 'rb'))
    self.possible_rule_prefixes = pickle.load(open(PATH + 'possible_rule_prefixes.pkl', 'rb'))
    self.endings = ProxyUnicodeGetter(PATH + 'endings.shv')
    self.normal_forms = ProxyIntGetter(PATH + 'normal_forms.shv')
    self.rule_freq = {}

  def calculate_rule_freq(self):
    """
    Подсчитать частоту, с которой встречаются различные правила.
    Требуется для предсказателя, чтобы выбирать наиболее распространенные
    варианты.
    """
    for lemma in self.lemmas:
      for paradigm_id in self.lemmas[lemma]:
        self.rule_freq[paradigm_id] = self.rule_freq.get(paradigm_id, 0)+1


  def analyze(self, word):
    """
    Возвращает (lemma, paradigm_id, rule) со всеми вариантами разбора слова.

    lemma - с какой леммой слово разобрали;
    paradigm_id - номер парадигмы;
    rule - подходящее правило в парадигме.

    Подклассы, использующие специализированные структуры для хранения
    словарей, могут реализовать этот метод эффективнее.
    """

    rules = self.rules
    lemmas = self.lemmas

    # Основная проверка по словарю: разбиваем слово на 2 части,
    # считаем одну из них леммой, другую окончанием, пробуем найти
    # лемму в словаре; если нашли, то пробуем найти вариант разбора
    # с подходящим окончанием.
    for lemma, suffix in get_split_variants(word):
      if lemma in lemmas:
        for paradigm_id in lemmas[lemma]:
          paradigm = rules[paradigm_id]
          if suffix in paradigm:
            for rule in paradigm[suffix]:
              yield lemma, paradigm_id, (suffix, rule[0], rule[1])

    # Вариант с пустой леммой (например, ЧЕЛОВЕК - ЛЮДИ).
    # У таких слов в словарях основа записана как "#".
    for paradigm_id in lemmas['#']:
      paradigm = rules[paradigm_id]
      if word in paradigm:
        for rule in paradigm[word]:
          yield '', paradigm_id, (word, rule[0], rule[1])


  def _check_self(self):
    """ Проверить словарь на корректность """
    paradigm_ids = self.rules.keys()

    print('checking paradigms...')
    # правила
    for paradigm_id, paradigm_rules in self.rules.iteritems():
      if not paradigm_rules:
        print ('  no rules for paradigm %d' % paradigm_id)
    print ('%d paradigms were checked' % len(paradigm_ids))

    print ('checking lemmas...')
    # леммы
    for base, paradigms in self.lemmas.iteritems():
      for id in paradigms:
        if id not in paradigm_ids:
          print ('  invalid paradigm %d for lemma %s' % (id, base))
    print ('%d lemmas were checked' % len(self.lemmas.keys()))

  def _check_other(self, other):
    """ Сравнить свои данные с данными из другого источника, считая
    самого себя непогрешимым.  """

    print ("checking other's paradigms...")
    errors = 0
    for paradigm_id, rules in self.rules.iteritems():
      if paradigm_id not in other.rules:
        print ("  paradigm %d doesn't exist" % paradigm_id)
        errors += 1
        continue

      # FIXME: проверить значения
#      # приводим все к tuple
#      other_rules = [tuple(r) for r in other.rules[paradigm_id]]
#      if rules != other_rules:
#        print ('  paradigm %s is incorrect:' % paradigm_id)
#        pprint(rules)
#        print ('!=')
#        pprint(other_rules)
#        print ('--------------------')
#        errors += 1

    if errors:
      print ('%d errors found.' % errors)

    errors = 0
    print ("checking other's lemmas...")
    for lemma, paradigms in self.lemmas.iteritems():
      if lemma not in other.lemmas:
        print ("  lemma %s doesn't exist" % lemma)
        errors += 1
        continue
      other_paradigms = other.lemmas[lemma]
      if paradigms != other_paradigms:
        print ('  lemma %s is incorrect: %s != %s' % (lemma, other_paradigms, paradigms))
        errors += 1
    if errors:
      print ('%d errors found.' % errors)
